using System;
using System.DHTML;
using Ext;
using Ext.data;
using Ext.form;
using Ext.grid;
using Ext.menu;

namespace PageScripts {
    public class ProductsPage {
        public static void main(Dictionary args) {
            ScriptSharpAdapter.init();
            ExtClass.onReady(new AnonymousDelegate(delegate() { new ProductsPage().init(); }), null, false);
        }

        private readonly int _pageSize = 30;
        private Grid _productsGrid;
        private Menu _gridContextMenu;
        private BorderLayout _layout;
        private CategoriesDialog _categoriesDialog;
        private SuppliersDialog _suppliersDialog;
        private ProductDetailsForm _productForm;
        private Dictionary _buttons;

        public void init() {
            QuickTips.init();

            CreateGrid();
            CreateLayout();
            CreatePager();
            CreateToolbar();
            CreateContextMenu();
            CreateThemeCombo();
            CreateProductForm();

            _productsGrid.getDataSource().load(new Dictionary("params", new Dictionary("start", 0, "limit", _pageSize)));
        }

        public Store GetCategoriesStore() {
            if (Script.IsNullOrUndefined(_categoriesDialog)) CreateCategoriesDialog();
            return _categoriesDialog.GetCategoriesStore();
        }

        public Store GetSuppliersStore() {
            if (Script.IsNullOrUndefined(_suppliersDialog)) CreateSuppliersDialog();
            return _suppliersDialog.GetSuppliersStore();
        }

        private void CreateGrid() {
            Store ds = CreateStore("ListProducts");
            ds.on(StoreEvents.load, 
                  new StoreLoadDelegate(delegate(Store store, Record[] records, object options) {
                        int count = _productsGrid.getColumnModel().getColumnCount();
                        for (int i = 0; i < count; i++) {
                            _productsGrid.getView().autoSizeColumn(i, true);
                        }
                  }), 
                  this, 
                  null
            );
            ds.setDefaultSort("ProductName", "ASC");

            ColumnModel cm = new ColumnModel(new Dictionary[] {
                new ColumnModelConfig().header("Name")             .dataIndex("ProductName")   .ToDictionary(),
                new ColumnModelConfig().header("Supplier Name")    .dataIndex("SupplierName")   .ToDictionary(),
                new ColumnModelConfig().header("Category Name")    .dataIndex("CategoryName")   .ToDictionary(),
                new ColumnModelConfig().header("Quantity Per Unit").dataIndex("QuantityPerUnit").ToDictionary(),
                new ColumnModelConfig().header("Unit Price")       .dataIndex("UnitPrice")      .ToDictionary(),
                new ColumnModelConfig().header("Units In Stock")   .dataIndex("UnitsInStock")   .ToDictionary(),
                new ColumnModelConfig().header("Units On Order")   .dataIndex("UnitsOnOrder")   .ToDictionary(),
                new ColumnModelConfig().header("Reorder Level")    .dataIndex("ReorderLevel")   .ToDictionary(),
                new ColumnModelConfig().header("Discontinued")     .dataIndex("Discontinued")   .ToDictionary(),
            });
            cm.defaultSortable = true;
            
            _productsGrid = new Grid("product-grid",
                new GridConfig()
                    .ds(ds)
                    .cm(cm)
                    .selModel(new RowSelectionModel(new Dictionary("singleSelect", true)))
                    .enableColLock(true)
                    .monitorWindowResize(true)
                    .loadMask(true)
                    .ToDictionary()
            );
            

            _productsGrid.on(GridEvents.contextmenu,
                new GridContextmenuDelegate(delegate(EventObject e) {
                    if ((bool)e.shiftKey) return;
                    e.stopEvent();
                    _gridContextMenu.showAt(e.getXY(), null);
                }),
                this,
                null);

            _productsGrid.on(GridEvents.rowdblclick, new GridRowdblclickDelegate(
                delegate(Grid obj, int rowIndex, EventObject e) {
                    EditSelectedProduct();
                }),
                this, 
                null);

            _productsGrid.render();
        }

        private void CreateLayout() {
            _layout = new BorderLayout(Document.Body, new Dictionary(
                "north", new BorderLayoutConfig().split(false).initialSize(70).titlebar(false).ToDictionary(),
                "west", new BorderLayoutConfig().split(true).initialSize(200).titlebar(true).autoScroll(true).collapsible(true).collapsed(true).ToDictionary(),
                "center", new BorderLayoutConfig().titlebar(true).autoScroll(true).tabPosition("top").ToDictionary()
            ));
            _layout.beginUpdate();
            _layout.add("north", new ContentPanel("north", "North", null));
            _layout.add("west", new ContentPanel("west", "Navigation", null));
            _layout.add("center", new GridPanel(_productsGrid, new GridPanelConfig().autoCreate(true).title("Products").ToDictionary()));
            _layout.endUpdate(false);
        }

        private Store CreateStore(string action) {
            if (Script.IsNullOrUndefined(action)) action = "listProducts";

            return new Store(
                new StoreConfig()
                    .proxy(new HttpProxy(new HttpProxyConfig().url("DataHandler.aspx").ToDictionary()))
                    .reader(new JsonReader(
                        new JsonReaderConfig()
                            .root("results")
                            .totalProperty("totalCount")
                            .id("ProductID")
                            .ToDictionary(),
                        new string[] {
                            "ProductID", "ProductName", "SupplierID", "CategoryID",
                            "QuantityPerUnit", "UnitPrice", "UnitsInStock", "UnitsOnOrder",
                            "ReorderLevel", "Discontinued", "SupplierName", "CategoryName"
                        }
                    ))
                    .remoteSort(true)
                    .baseParams(new Dictionary("action", action))
                    .ToDictionary()
            );
        }

        private void CreatePager() {
            new PagingToolbar(
                _productsGrid.getView().getFooterPanel(true),
                _productsGrid.getDataSource(),
                new PagingToolbarConfig()
                    .pageSize(_pageSize)
                    .displayInfo(true)
                    .displayMsg("Displaying items {0} - {1} of {2}")
                    .emptyMsg("No items to display")
                    .ToDictionary()
                    
            );
        }

        private void CreateToolbar() {
            ToolbarClass tb = new ToolbarClass(_productsGrid.getView().getHeaderPanel(true), null, null);
            _buttons = new Dictionary();
            _buttons["new"] = tb.addButton(UIHelper.CreateButton("New Product", "Add New Product", "add", AddNewProduct, this));
            _buttons["edit"] = tb.addButton(UIHelper.CreateButton("Edit Product", "Edit the selected Product", "edit", EditSelectedProduct, this));
            _buttons["del"] = tb.addButton(UIHelper.CreateButton("Delete Product", "Delete the selected Product", "delete", DeleteSelectedProduct, this));
            _buttons["ref"] = tb.addButton(UIHelper.CreateButton("Refresh", "Refresh the list of Products", "refresh", RefreshProductList, this));
            tb.add("-");
            _buttons["cats"] = tb.addButton(UIHelper.CreateButton("Product Categories", "Edit the Product Categories", "container", ShowProductCategories, this));
            _buttons["sups"] = tb.addButton(UIHelper.CreateButton("Product Suppliers", "Edit the Product Suppliers", "container", ShowProductSuppliers, this));

            // add a greedy spacer
            ExtClass.get(ExtClass.get(tb.addSpacer().getEl()).dom.ParentNode).setStyle("width", "100%");

            _buttons["help"] = tb.addButton(UIHelper.CreateButton("Help", "Help on this page", "help", ShowHelp, this));
        }

        private void CreateContextMenu() {
            _gridContextMenu = new Menu(new Dictionary(
                "id", "mainMenu",
                "items", new object[] {
                    new Dictionary("icon", "js/ext-1.1/images/table_edit.png", "text", "Edit Product", "scope", this, "handler", new Callback(EditSelectedProduct)), 
                    new Dictionary("icon", "js/ext-1.1/images/table_delete.png", "text", "Delete Product", "scope", this, "handler", new Callback(DeleteSelectedProduct)), 
                    "-",
                    new Dictionary("icon", "js/ext-1.1/images/table_add.png", "text", "Add New Product", "scope", this, "handler", new Callback(AddNewProduct)), 
                    "-",
                    new Dictionary("icon", "js/ext-1.1/images/table_go.png", "text", "Show Product Categories", "scope", this, "handler", new Callback(ShowProductCategories)), 
                    new Dictionary("icon", "js/ext-1.1/images/table_go.png", "text", "Show Product Suppliers", "scope", this, "handler", new Callback(ShowProductSuppliers))
                }
            ));
        }

        private void CreateThemeCombo() {
            ComboBox combo = new ComboBox(
                new ComboBoxConfig()
                    .typeAhead(true)
                    .triggerAction("all")
                    .transform("themes")
                    .forceSelection(true)
                    .editable(false)
                    .emptyText("Choose a theme ...")
                    .ToDictionary()
            );
            combo.setValue("");
            combo.on(ComboBoxEvents.select, 
                new ComboBoxSelectDelegate(
                    delegate(ComboBox cb, Record rec, int index) {
                        Window.Navigate("Products.aspx?theme=" + cb.getValue());
                    }
                ), 
                this, null);
        }

        private void CreateProductForm() {
            _productForm = new ProductDetailsForm(this);
            _productForm.on(ProductsDetailsFormEvents.inserted, new ProductsDetailsFormInsertedDelegate(
                delegate(ProductDetailsForm form, bool success) {
                    if (success) {
                        _productsGrid.getDataSource().reload(null);
                    }
                }
            ), this, null);
            _productForm.on(ProductsDetailsFormEvents.updated, new ProductsDetailsFormUpdatedDelegate(
                delegate(ProductDetailsForm form, bool success, Dictionary values) {
                    if (success) {
                        Record row = _productsGrid.getDataSource().getById((string)values["ProductID"]);
                        foreach (DictionaryEntry v in values) {
                            row.set(v.Key, v.Value);
                        }
                        _productsGrid.getDataSource().commitChanges();
                    }
                }
            ), this, null);
            _productForm.Init();
        }

        private void DeleteSelectedProduct() {
            Record row = ((RowSelectionModel)_productsGrid.getSelectionModel()).getSelected();
            if (Script.IsNullOrUndefined(row)) {
                MessageBox.alert("Error", "Please select a Product to delete!", null, null);
                return;
            }
            MessageBox.confirm("Really Delete?", "Are you sure you want to delete \"" + row.get("ProductName") + "\"?",
                new MessageBoxResponseDelegate(delegate(string button, string text) {
                    if (button != "yes") return;

                    // don't actually delete, just remove from the grid
                    //Store ds = CreateStore("delete");
                    //ds.load(new Dictionary("params", new Dictionary("ProductID", row.get("ProductID"))));
                    
                    _productsGrid.getDataSource().remove(row);
                }), 
                this);
        }

        private void EditSelectedProduct() {
            Record row = ((RowSelectionModel)_productsGrid.getSelectionModel()).getSelected();
            if (Script.IsNullOrUndefined(row)) {
                MessageBox.alert("Error", "Please select a Product to delete!", null, null);
                return;
            }
            _gridContextMenu.hide(false);
            _productForm.Show(FormMode.Update, ((Button)_buttons["edit"]).getEl(), row);
        }

        private void AddNewProduct() {
            _gridContextMenu.hide(false);
            _productForm.Show(FormMode.Insert, ((Button)_buttons["new"]).getEl(), null);
        }

        private void RefreshProductList() {
            _productsGrid.getDataSource().reload(null);
        }

        private void CreateCategoriesDialog() {
            _categoriesDialog = new CategoriesDialog();
            _categoriesDialog.on(CategoriesDialogEvents.categoryupdated, new CategoriesDialogUpdatedDelegate(
                delegate(Dictionary newValues) {
                    _productsGrid.getDataSource().each(new GenericOneArgDelegate(delegate(object row) {
                        Record record = (Record)row;
                        if (record.get("CategoryID") == newValues["CategoryID"]) {
                            record.set("CategoryName", newValues["CategoryName"]);
                        }
                     }), this);
                    _productsGrid.getDataSource().commitChanges();
                }    
            ), this, null);
            _categoriesDialog.on(CategoriesDialogEvents.categorydeleted, new CategoriesDialogDeletedDelegate(
                delegate(int categoryId) {
                    _productsGrid.getDataSource().each(new GenericOneArgDelegate(delegate(object row) {
                        Record record = (Record)row;
                        if ((int)record.get("CategoryID") == categoryId) {
                            _productsGrid.getDataSource().remove(record);
                        }
                     }), this);
                }    
            ), this, null);
        }

        private void ShowProductCategories() {
            if (Script.IsNullOrUndefined(_categoriesDialog)) CreateCategoriesDialog();
            _categoriesDialog.Show(((Button)_buttons["cats"]).getEl());
        }

        private void CreateSuppliersDialog() {
            _suppliersDialog = new SuppliersDialog();
            _suppliersDialog.on(SuppliersDialogEvents.supplierupdated, new SuppliersDialogUpdatedDelegate(
                delegate(Dictionary newValues) {
                    _productsGrid.getDataSource().each(new GenericOneArgDelegate(delegate(object row) {
                        Record record = (Record)row;
                        if (record.get("SupplierID") == newValues["SupplierID"]) {
                            record.set("SupplierName", newValues["CompanyName"]);
                        }
                    }), this);
                    _productsGrid.getDataSource().commitChanges();
                }
            ), this, null);
            _suppliersDialog.on(SuppliersDialogEvents.supplierdeleted, new SuppliersDialogDeletedDelegate(
                delegate(int supplierId) {
                    _productsGrid.getDataSource().each(new GenericOneArgDelegate(delegate(object row) {
                        Record record = (Record)row;
                        if ((int)record.get("SupplierID") == supplierId) {
                            _productsGrid.getDataSource().remove(record);
                        }
                    }), this);
                }
            ), this, null);
            
        }

        private void ShowProductSuppliers() {
            if (Script.IsNullOrUndefined(_suppliersDialog)) CreateSuppliersDialog();
            _suppliersDialog.Show(((Button)_buttons["sups"]).getEl());
        }

        private void ShowHelp() {
            MessageBox.alert("Help", "Coming Soon ...", null, null);
        }
    }
}